const Mat = {
  "Mat" : class Mat extends Array{
    // 使用行列值来初始化矩阵
    constructor(props=[1,1]){
      // 参数为形状
      if(props.length === 2){
        super(props[0]);
        if(!isNaN(props[0]) && !isNaN(props[1]) && props[0] > 0 && props[1] > 0){
          this.shape = props;

          this.fillWithNumber(Number.NaN);
        }
        else{
          this.copyFrom(props);
        }
      }
      else if(props instanceof Array){
        super(props.length);
        this.copyFrom(props);
      }
      else{
        super();
        throw new Error('无法接收参数类型');
      }
    }

    fillWithNumber(num){
      const shape = this.shape;

      for(let r = 0; r < shape[0]; r++){
        this[r] = [];
        for(let c = 0; c < shape[1]; c++){
          this[r][c] = parseFloat(num);
        }
      }

    }

    // 从其他数据源复制数据
    copyFrom(dat){
      if(!(dat instanceof Array)) return;
      let shape;
      this.length = 0;

      for(let i = 0, il = dat.length; i < il; i++){
        this[i]=[];
        if(dat[i] instanceof Array){
          if(!shape) shape = [dat.length, dat[i].length];
          for(let j = 0, jl = dat[i].length; j < jl; j++){
            this[i][j] = parseFloat(dat[i][j]);
          }
        }
        else{
          if(!shape) shape = [dat.length, 1];
          this[i][0] = parseFloat(dat[i]);
        }
      }

      this.shape = shape;
    }

    rows(){
      return this.shape[0];
    }

    cols(){
      return this.shape[1];
    }

    T(){
      return this.transpose();
    }

    // 转置
    transpose(){
      let mat = new Mat([this.shape[1], this.shape[0]]);
      for(let r = 0; r < mat.shape[0]; r ++){
        for(let c = 0; c < mat.shape[1]; c++){
          mat[r][c] = this[c][r];
        }
      }
      return mat;
    }

    // 切分
    // row:行起始位置和结束位置,如果只有一个参数则默认到行结束
    // col:列起始位置和结束位置,如果只有一个参数则默认到列结束
    slice(row, col){
      let startRow = 0;
      let endRow   = this.rows();
      let startCol = 0;
      let endCol   = this.cols();

      if(row !== undefined){
        if(row instanceof Array && row.length === 2){
          startRow = parseInt(row[0]);
          endRow   = parseInt(row[1]);
        }
        else if(!isNaN(row)){
          startRow = parseInt(row);
          endRow   = startRow + 1;
        }
        else{
          return Number.NaN;
        }
      }
      if(col !== undefined){
        if(col instanceof Array && col.length === 2){
          startCol = parseInt(col[0]);
          endCol   = parseInt(col[1]);
        }
        else if(!isNaN(col)){
          startCol = parseInt(col);
          endCol   = endCol + 1;
        }
        else{
          return Number.NaN;
        }
      }
      // 判断范围是有效
      if(startRow >= endRow || startRow >= this.rows() || endRow > this.rows() || startRow < 0){
        return Number.NaN;
      }
      if(startCol >= endCol || startCol >= this.cols() || endCol > this.cols() || startCol < 0){
        return Number.NaN;
      }

      // console.log(startRow, endRow, startCol, endCol);
      let mat = new Mat([endRow - startRow, endCol - startCol]);
      
      for(let r = startRow; r < endRow; r++){
        for(let c = startCol; c < endCol; c++){
          mat[r-startRow][c-startCol] = this[r][c];
        }
      }

      return mat;
    }
    // 转换为向量
    toVector(){
      let vect = [];
      for(let r = 0; r < this.shape[0]; r ++){
          vect.push(...this[r]);
      }
      return vect;
    }

    print(){
      console.log(this);
    }
  },
  // 返回值全为0的矩阵
  "zeros":function(shape){
    let mat = new Mat.Mat(shape);
    mat.fillWithNumber(0.0);

    return mat;
  },
  // 返回全为1的矩阵
  "ones":function(shape){
    let mat = new Mat.Mat(shape);
    mat.fillWithNumber(1.0);

    return mat;
  },
  // 矩阵按位相加
  // 如果matB是个数，则将matA中的所有元素加matB
  "add":function(matA, matB){
    let mat = new Mat.Mat(matA.shape);

    if(matB instanceof Array){
      if(matA.shape[0] !== matB.shape[0] || matA.shape[1] !== matB.shape[1]){
        return Number.NaN;
      }
      
      for(let r = 0; r < mat.rows(); r++){
        for(let c = 0; c < mat.cols(); c++){
          mat[r][c] = matA[r][c] + matB[r][c];
        }
      }
    }
    else if(!isNaN(matB)){
      for(let r = 0; r < mat.rows(); r++){
        for(let c = 0; c < mat.cols(); c++){
          mat[r][c] = matA[r][c] + matB;
        }
      }
    }
    else{
      return Number.NaN
    }

    return mat;
  },
  // 矩阵按位相乘
  // 如果matB是个数，则将matA中的所有元素乘以matB
  "multiply":function(matA, matB){
    let mat = new Mat.Mat(matA.shape);

    if(matB instanceof Array){
      if(matA.shape[0] !== matB.shape[0] || matA.shape[1] !== matB.shape[1]){
        return Number.NaN;
      }
      
      for(let r = 0; r < mat.rows(); r++){
        for(let c = 0; c < mat.cols(); c++){
          mat[r][c] = matA[r][c] * matB[r][c];
        }
      }
    }
    else if(!isNaN(matB)){
      for(let r = 0; r < mat.rows(); r++){
        for(let c = 0; c < mat.cols(); c++){
          mat[r][c] = matA[r][c] * matB;
        }
      }
    }
    else{
      return Number.NaN
    }

    return mat;
  },
  // 矩阵乘法
  "mul":function(matA, matB){

    if(matA.cols() !== matB.rows()){
      return Number.NaN;
    }

    let mat = new Mat.Mat([matA.rows(), matB.cols()]);

    for(let r = 0; r < mat.rows(); r++){
      for(let c = 0; c < mat.cols(); c++){
        mat[r][c] = 0.0;
        for(let i = 0; i < matA.cols(); i++){
          mat[r][c] += matA[r][i]*matB[i][c];
        }
      }
    }

    return mat;
  },
  // 点乘
  "dot":function(matA, matB){
    let vectA = matA.toVector();
    let vectB = matB.toVector();
    if(vectA.length !== vectB.length){
      return Number.NaN;
    }
    
    let sum = 0.0;
    for(let i = 0,  il = vectA.length; i < il; i++){
      sum += vectA[i]*vectB[i];
    }

    return sum;
  }
}

export default Mat;